<!--
 * @Author: 吴世扬
 * @Date: 2022-10-12 10:05:48
 * @LastEditors: 吴世扬 18368095041@163.com
 * @LastEditTime: 2025-04-09 11:27:27
 * @FilePath: /vue3-admin/src/components/ui/CustomChart/CustomChart.vue
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
-->

<script lang="ts" setup>
import {
    defineProps,
    toRefs,
    onMounted,
    ref,
    onBeforeUnmount,
    watch,
    toRaw
} from 'vue';
// echarts@5.4.0
import * as Echarts from 'echarts';
// import type { DatasetComponentOption } from 'echarts';
import { getPercentWithPrecision } from './utils';
import type { PieItemValue } from './utils';
import { debounce } from './utils';

const props = withDefaults(
    defineProps<{
        datasetSource?: unknown[]; // 数据集 https://echarts.apache.org/zh/option.html#dataset
        extraOption?: Record<string, unknown>;
        legendShowPercent?: boolean;
    }>(),
    {
        datasetSource: () => [[]],
        extraOption: () => ({}),
        legendShowPercent: false
    }
);
let option: Record<string, any> = {};
let chart: Echarts.ECharts | null = null;
const chartView = ref<HTMLDivElement | null>(null);
const { datasetSource, extraOption, legendShowPercent } = toRefs(props);

const isPieItemValue = (arg: unknown): arg is PieItemValue => {
    const asPieItemValue = arg as PieItemValue;
    if (
        typeof asPieItemValue.name === 'string' &&
        typeof asPieItemValue.value === 'number'
    ) {
        return true;
    }
    return false;
};
// 合并选项
const assembleOption = () => {
    // option =
    //     merge(option, toRaw(extraOption.value), {
    //         dataset: { source: toRaw(datasetSource.value) }
    //     }) || {};
    option = toRaw(extraOption.value);
    option.dataset = { source: toRaw(datasetSource.value) };
    if (legendShowPercent.value) {
        const formatter = (name: string) => {
            const index = datasetSource.value.findIndex((item) => {
                if (isPieItemValue(item)) {
                    return item.name === name;
                }
                throw new Error(
                    'legendShowPercent设为true，则datasetSource必须传{ name: string; value: number }的格式'
                );
            });
            const percent = getPercentWithPrecision(
                (datasetSource.value as PieItemValue[]).map(
                    (item) => item.value
                ),
                index,
                2
            );
            return `${name} ${percent}%`;
        };
        if (option.legend === undefined) {
            option.legend = { formatter };
        } else {
            option.legend.formatter = formatter;
        }
        // option = merge(option, { legend: { formatter } }) || {};
    }
};
// 数据更新
const updateChartView = debounce(() => {
    if (!chart) return;
    assembleOption();
    chart.setOption(option, true);
}, 1000);
// 当窗口缩放时，echart动态调整自身大小 (窗口缩放)
const handleWindowResize = () => {
    if (!chart) return;
    chart.resize();
};
watch(
    [() => datasetSource, () => extraOption],
    () => {
        updateChartView();
    },
    {
        deep: true
    }
);
onMounted(() => {
    chartView.value && (chart = Echarts.init(chartView.value)); // 初始化Echart实例
    updateChartView(); // 图表数据有更新
    window.addEventListener('resize', handleWindowResize); // 窗口大小变化
});
onBeforeUnmount(() => {
    window.removeEventListener('resize', handleWindowResize);
});
</script>

<template>
    <div class="chart" ref="chartView">暂无数据</div>
</template>

<style scoped lang="scss">
.chart {
    width: 100%;
    height: 100%;
}
</style>
